////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "ShadowCasterEntityHandler.hpp"

#include <SmegCore/Entity/BaseEntity.hpp>
#include <SmegCore/Entity/EntityManager.hpp>

#include <SmegLight/Entity/ShadowCasterEntity.hpp>
#include <SmegLight/Hull/CircleHull.hpp>
#include <SmegLight/Hull/ConvexHull.hpp>
#include <SmegLight/Light/LightSystem.hpp>

#include "../../tinyxml2/tinyxml2.h"
#include "../../Canvas/SmegEditorCanvas.hpp"

#include "../ObjectHandlerFactory.hpp"
#include "../ObjectHandlers.h"

////////////////////////////////////////////////////////////
/// Constructor
////////////////////////////////////////////////////////////
ShadowCasterEntityHandler::ShadowCasterEntityHandler() :
    BaseEntityHandler(),
    m_pHullHandler( NULL ),
    m_eCurrentHull( eHull_NoHull )
{
}

////////////////////////////////////////////////////////////
/// Copy Constructor
////////////////////////////////////////////////////////////
ShadowCasterEntityHandler::ShadowCasterEntityHandler( const ShadowCasterEntityHandler& _Copy ) :
    BaseEntityHandler( _Copy ),
    m_pHullHandler( NULL ),
    m_eCurrentHull( _Copy.m_eCurrentHull )
{
    if ( _Copy.m_pHullHandler ) {
        m_pHullHandler = static_cast<BaseObjectHandler*>(_Copy.m_pHullHandler->Clone());
    }
}

////////////////////////////////////////////////////////////
/// Init the handler and setup the properties
/// BaseEntityHandler::InitFromGrid need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool ShadowCasterEntityHandler::InitFromGrid( wxPropertyGrid* _pPropertyGrid ) {
    m_pObject = new smeg::light::ShadowCasterEntity( m_pCanvas );

    if ( BaseEntityHandler::InitFromGrid( _pPropertyGrid ) ) {
        ChangeHull( eHull_Texture, _pPropertyGrid );

        return true;
    }

    return false;
}
    
////////////////////////////////////////////////////////////
/// Init the handler from an XMLElement
/// BaseEntityHandler::InitFromXML need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool ShadowCasterEntityHandler::InitFromXML( tinyxml2::XMLElement* _pElement, const wxString& _ProjectPath ) {
    bool successInit = true;

    // Get the infos
    tinyxml2::XMLElement* hullElem = _pElement->FirstChildElement( "Object" );

    m_pObject = new smeg::light::ShadowCasterEntity( m_pCanvas, m_pCanvas->GetViewCenter() );
    
    if ( BaseEntityHandler::InitFromXML( _pElement, _ProjectPath ) ) {
        smeg::light::ShadowCasterEntity* shadowCasterEntity = static_cast< smeg::light::ShadowCasterEntity* >( m_pObject );

        if ( hullElem ) {
            wxString hullName = hullElem->Attribute( "name" );
            
            if ( "Circle Hull" == hullName ) {
                m_pHullHandler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( "Circle Hull" );
                m_eCurrentHull = eHull_Circle;
            } else if ( "Convex Hull" == hullName ) {
                m_pHullHandler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( "Convex Hull" );
                m_eCurrentHull = eHull_Convex;
            } else if ( "Texture Hull" == hullName ) {
                m_pHullHandler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( "Texture Hull" );
                m_eCurrentHull = eHull_Texture;
            }

            if ( m_pHullHandler->Init( m_pCanvas, hullElem, _ProjectPath ) ) {
                shadowCasterEntity->SetHull( static_cast< smeg::light::Hull* >( m_pHullHandler->GetObject() ) );
            } else {
                m_eCurrentHull = eHull_NoHull;
                successInit = false;
            }
        }
    } else {
        successInit = false;
    }

    if ( !successInit ) {
        delete m_pHullHandler;
        m_pHullHandler = NULL;
    }

    return successInit;
}
    
////////////////////////////////////////////////////////////
/// Return the value of a property
////////////////////////////////////////////////////////////
wxString ShadowCasterEntityHandler::GetValueAsString( const wxString& _PropertyName ) const {
    wxString baseValue = BaseEntityHandler::GetValueAsString( _PropertyName );
    if ( wxEmptyString == baseValue && m_pHullHandler ) {
        return m_pHullHandler->GetValueAsString( _PropertyName );
    } else {
        return baseValue;
    }
}
    
////////////////////////////////////////////////////////////
/// Return the value of a property with a choice
///
/// \param _pChoiceProperty :    Property we want the choice
///
/// \return The value of the choice
///
////////////////////////////////////////////////////////////
int ShadowCasterEntityHandler::GetChoiceValue( wxPGProperty* _pChoiceProperty ) {
    if ( "Hull Type" == _pChoiceProperty->GetName() ) {
        smeg::light::Hull* hull = static_cast< smeg::light::ShadowCasterEntity* >( m_pObject )->GetHull();

        if ( !hull ) {
            return eHull_NoHull;
        } else if ( dynamic_cast< smeg::light::CircleHull* >(hull) ) {
            return eHull_Circle;
        } else if ( dynamic_cast< smeg::light::ConvexHull* >(hull) ) {
            return eHull_Convex;
        } else {
            return eHull_NoHull;
        }
    }

    return BaseEntityHandler::GetChoiceValue( _pChoiceProperty);
}
    
////////////////////////////////////////////////////////////
/// Handle the change of a property and apply it to the object
////////////////////////////////////////////////////////////
bool ShadowCasterEntityHandler::OnPropertyChanged( wxPropertyGrid* _pPropertyGrid, wxPGProperty* _pChangedProperty ) {
    BaseEntityHandler::OnPropertyChanged( _pPropertyGrid, _pChangedProperty );

    smeg::core::BaseEntity* baseEntity = static_cast< smeg::core::BaseEntity* >( m_pObject );
    
    // Handle changes in values, as needed
    const wxString& propName(_pChangedProperty->GetName());
    if ( "Hull Type" == propName ) {
        ChangeHull( (eHullType)_pChangedProperty->GetValue().GetAny().As<int>(), _pPropertyGrid );
    } else if ( m_pHullHandler ) {
        return m_pHullHandler->OnPropertyChanged( _pPropertyGrid, _pChangedProperty );
    } else {
        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////
/// Handle the double click on a property
////////////////////////////////////////////////////////////
bool ShadowCasterEntityHandler::OnPropertyDoubleClick( wxPropertyGrid* _pPropertyGrid, wxPGProperty* _pChangedProperty ) {
    if ( m_pHullHandler && m_pHullHandler->OnPropertyDoubleClick( _pPropertyGrid, _pChangedProperty ) ) {
        return true;
    } else {
        return BaseEntityHandler::OnPropertyDoubleClick( _pPropertyGrid, _pChangedProperty );
    }
}

////////////////////////////////////////////////////////////
/// Changing the type of Hull
////////////////////////////////////////////////////////////
void ShadowCasterEntityHandler::ChangeHull( ShadowCasterEntityHandler::eHullType _type, wxPropertyGrid* _pPropertyGrid ) {
    if ( m_eCurrentHull != _type ) {
        m_eCurrentHull = _type;

        delete m_pHullHandler;
        m_pHullHandler = NULL;
        smeg::light::ShadowCasterEntity* pEntity = static_cast< smeg::light::ShadowCasterEntity* >( m_pObject );
        pEntity->RemoveHull();

        switch ( m_eCurrentHull ) {
        case eHull_Circle:
            m_pHullHandler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( "Circle Hull" );
            break;

        case eHull_Convex:
            m_pHullHandler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( "Convex Hull" );
            break;

        case eHull_Texture:
            m_pHullHandler = ObjectHandlerFactory::GetInstance()->CreateObjectHandler( "Texture Hull" );
            static_cast< TextureHullHandler* >(m_pHullHandler)->SetTexture( m_CurrentSpriteFilename.GetFullPath() );
            break;
        }

        if ( m_pHullHandler ) {
            if ( m_pHullHandler->Init( m_pCanvas, _pPropertyGrid, pEntity->GetCenter() ) ) {
                pEntity->SetHull( static_cast< smeg::light::Hull* >( m_pHullHandler->GetObject() ) );
            } else {
                delete m_pHullHandler;
                m_pHullHandler = NULL;
                m_eCurrentHull = eHull_NoHull;
            }
        }

        _pPropertyGrid->GetProperty("Hull Type")->SetValue( m_eCurrentHull );
        m_pCanvas->SetSelectedObject( m_pObject );
    }
}
   
////////////////////////////////////////////////////////////
/// Create an XML string with the value of the object
////////////////////////////////////////////////////////////
wxString ShadowCasterEntityHandler::InnerXMLString( const wxString& _ProjectPath, const wxString& _Tab ) const {
    if ( m_pHullHandler ) {
        return BaseEntityHandler::InnerXMLString( _ProjectPath, _Tab ) +
            m_pHullHandler->ToXMLString( _ProjectPath, _Tab );
    } else {
        return BaseEntityHandler::InnerXMLString( _ProjectPath, _Tab );
    }
}